import os

import pygame

import libs.map_handler as map_handler
import libs.player_manager as player_manager

class ViewableArea(pygame.Surface):
    """ A class to render the visible area of the current map """
    def __init__(self):
        """ Default Constructor, initialize parent passing the size of the map """
        pygame.Surface.__init__(self, screen.get_size()) # Size of the map

        self.convert()
        self.fill((255, 255, 255))
        screen.blit(self, (0,0))
        pygame.display.flip()

class MapViewArea(pygame.Surface):
    """
    This class will render the viewable map area onto a surface. We shall make
    this singleton a child of a surface itself so we can blit this object without
    creating a surface to hold this object.
    """
    textures = {}
    def __init__(self, mapName):
        """
        Constructor, ensure that the current map is loaded into memory for
        fast access to the rendering

        @param mapName - string representation of a map to load.
        """

        # Call the parent constructor then paint the screen black
        pygame.Surface.__init__(self, (576, 576))
        self.convert()
        self.fill((0, 0, 0))
        screen.blit(self, (0, 0))
        pygame.display.update()

        # Set the default X and Y texture as the centre
        self.currentXTexture = self.currentYTexture = 0

        # Load the map into memory
        self.mapInstance = map_handler.maps[mapName]
        self.mapInstance.load()

    def getTexture(self, x, y):
        """
        Return the texture instance of a given co-ordinate

        @param x - the x co-ordinate
        @param y - the y co-ordinate
        @return Texture - instance of a texture
        """
        return self.textures[x][y]

    def setTexture(self, x, y, texture):
        """
        Set the given co-ordinate to hold the texture instance

        @param x - the x co-ordinate
        @param y - the y co-ordinate
        @param texture - instance of a texture
        """
        if not isinstance(texture, map_handler.Texture):
            raise map_handler.MapError("Texture must be type Texture, got type %s" % type(texture).__name__)
        self.textures[x][y] = texture

    def blitToScreen(self, centreTexture = None):
        """ Note: Build top - bottom rather than left to right """
        width  = self.mapInstance.data['mapInfo']['width']
        height = self.mapInstance.data['mapInfo']['height']
        if centreTexture == None:
            centreTexture = (self.currentXTexture, self.currentYTexture)
        centreX, centreY = centreTexture
        startX = startY = 1
        ignoreXOffset = ignoreYOffset = False

        xOffset, yOffset = player_manager.player.getOffsets()

        """ Start building which viewable textures we can see... """
        if centreX > 5:
            """ Start the drawing at the 5 textures before the centre """
            startX = centreX - 5
        else:
            ignoreXOffset = True
        if centreY > 5:
            startY = centreY - 5
        else:
            ignoreYOffset = True

        #textures     = self.mapInstance.data['textures']
        #textureRange = textures[startX - 1 : startX + 8]
        #for index, textureList in enumerate(textureRange):
            #textureRange[index] = textureList[startY - 1 : startY + 8]

        textures = []


        """ Get the entire texture grid on the map and assign the range. """
        mapTextures  = self.mapInstance.data['textures']
        textureRange = textures[startX : startX + 9]
        for index, textureList in enumerate(textureRange):
            textureRange[index] = textureList[startY : startY + 9]

        if ignoreXOffset is True:
            """
            This is simple, we don't need to worry about building part textures
            at either side of the texture range so just assign the textures to
            hold the current data of the textureRange.
            """
            textures = textureRange
        else:
            """
            We need to build the offset and get the textures before and after
            the texture range. We need to crop the image according to the offset
            and ensure that the position of this cropped image is relative to the
            other indexes.
            """
            if xOffset < 0:
                """
                We need to delete the end index as we will rebuild it with
                cropped part textures
                """
                del textureRange[-1]
                xIndexLower = startX - 1
                xIndexUpper = startX + 8
            else:
                """
                We need to delete the first index as we will rebuild it with
                cropped part textures
                """
                del textureRange[0]
                xIndexLower = startX
                xIndexUpper = startX + 9
            textures[0] = []
            for index, texture in enumerate(textureRange):
                partTexture = map_handler.PartTexture( mapTextures[xIndexLower][startY + index].texture)
                partTexture.crop( (abs(xOffset), 64) )
                textures[0].append( partTexture )
            textures += textureRange
            textures.append([])
            for index, texture in enumerate(textureRange):
                partTexture = map_handler.PartTexture( mapTextures[xIndexUpper][startY + index].texture)
                partTexture.crop( (64 - abs(xOffset), 64), (64 - xOffset, 0) )
                textures[-1].append( partTexture )

        if ignoreYOffset is False:
            """ We need to build the offset of all the """

        currentXCoord = currentYCoord = 0
        for yTextureColumn in textures:
            for xTextureRow in yTextureColumn:
                xTextureRow.blit(self, )
            

pygame.init() # Initialize the PyGame interface and all of it's components
screen = pygame.display.set_mode((576, 800))
pygame.display.set_caption("The Final Kingdom")

clock = pygame.time.Clock()

view = ViewableArea()
mapView = MapViewArea("test_map")

def startup():
    while True:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    return
                if event.key == pygame.K_LEFT:
                    movePlayer(-1, 0)
                    mapView.blitToScreen()
                elif event.key == pygame.K_RIGHT:
                    movePlayer(1, 0)
                    mapView.blitToScreen()
                elif event.key == pygame.K_UP:
                    movePlayer(0, -1)
                    mapView.blitToScreen()
                elif event.key == pygame.K_DOWN:
                    movePlayer(0, 1)
                    mapView.blitToScreen()

def movePlayer(x, y):
    textureChangeX, textureChangeY = player_manager.player.move(x, y)
    if textureChangeX:
        mapView.currentXTexture += textureChangeX
    if textureChangeY:
        mapView.currentYTexture += textureChangeY

if __name__ == "__main__":
    startup()